package org.example.juc.lock;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 资源池
 */
public class LockDB {

    // 当前值
    private volatile int currentValue = 0;

    private Queue<Integer> resources;

    // 最大可用数量为300
    private static final int MAX_VALUE = 300;

    // 最小可用数量为1
    private static final int MIN_VALUE = 1;

    // 定义一个锁
    private ReentrantLock lock = new ReentrantLock();

    // 非空锁
    private Condition NOT_EMPTY = lock.newCondition();

    // 非满锁
    private Condition NOT_FULL = lock.newCondition();

    private static Unsafe unsafe;

    private static long valueOffset;

    private Thread createThread;

    /**
     * 活动数量
     */
    private AtomicInteger activeCount = new AtomicInteger(0);

    public LockDB() {
        try {
            Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
            unsafeField.setAccessible(true);
            unsafe = (Unsafe) unsafeField.get(null);

            Field currentValueField = LockDB.class.getDeclaredField("currentValue");
            currentValueField.setAccessible(true);
            valueOffset = unsafe.objectFieldOffset(currentValueField);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (MIN_VALUE > 0) {
            resources = new LinkedList<>();
            resources.offer(1);
            activeCount.getAndIncrement();
        }
        createThread = new Thread(new CreateThread());
        this.init();
    }

    public void init() {
        createThread.start();
    }

    /**
     * 生产者线程
     */
    class CreateThread implements Runnable {
        @Override
        public void run() {
            for (;;) {
                lock.lock();
                try {
                    // 判断如果当前值已经达到了最大值，不能继续生产了
                    if ((activeCount.get() + resources.size()) >= MAX_VALUE) {
                        System.out.println("资源池已经满了，阻塞，当前活动连接 = " + activeCount.get() + "，当前队列大小 = " + resources.size());
                        NOT_FULL.await();
                        continue;
                    }

                    // 生成一个新的连接
                    resources.offer(new Integer(1));
                    // 通知消费者可以继续消费了
                    NOT_EMPTY.signalAll();
                    System.out.println("资源池足够，继续生产");
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    public Integer getConnection() {
        // 自旋获取连接
        for(;;) {
            lock.lock();
            try {
                // 不为空时，资源足够，直接取即可
                if (!resources.isEmpty()) {
                    Integer result = resources.poll();
                    System.out.println("活动连接 = " + activeCount.getAndIncrement());
                    return result;
                }

                // 通知生产者生产资源
                NOT_FULL.signalAll();
                System.out.println("线程阻塞，等待生产者生产");
                NOT_EMPTY.await();
                // 非空才能往下执行
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }

    /**
     * 可用资源池
     * @return
     */
    public Integer getResources() {
        return resources.size();
    }

    public Integer getActiveCount() {
        return activeCount.get();
    }

    /**
     * 归还连接池
     * @param conn
     */
    public void close(Integer conn) {
        // 对于临界区资源的访问必须要进行lock
        lock.lock();
        try {
            activeCount.decrementAndGet();
            // 把资源归还到队列
            resources.offer(conn);
            // 通知其他等待连接的线程可以归还连接了
            NOT_EMPTY.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}
